#ifndef MIPSPROCESSORSTATE_H
#define MIPSPROCESSORSTATE_H


#include <iostream>
#include "crossbit/ProcessorState.h"
#include "string.h"

namespace crossbit {

		class MIPSProcessorState : public ProcessorState
		{
				public:
						/* total 35 internal registers numbered 0, 1, ..., 33 */
						enum PISA {
								$zero = 0,				// $0, zero-valued souce
								$at,					// $1, reserved by assembler
								$v0, $v1,				// $2-$3, fn return result regs
								$a0, $a1, $a2, $a3,			// $4-$7, fn argument value regs
								$t0, $t1, $t2, $t3, $t4, $t5, $t6, $t7, // $8-$15, temp regs, caller saved, general-purpose
								$s0, $s1, $s2, $s3, $s4, $s5, $s6, $s7, // $16-$23, saved regs, callee saved, general-purpose
								$t8, $t9,				// $24-$25, temp regs, caller saved, general-purpose
								$k0, $k1,				// $26-$27, reserved by OS
								$gp,					// $28, global pointer
								$sp,					// $29, stack pointer
								$s8,					// $30, saved reg, callee saved
								$ra,					// $31, return address reg
								$hi,					// high result register
								$lo,					// low result register
								EOR					//end of register
						};

						enum FP {					//Float point register
								$f0 = 0,
								$f1,
								$f2,
								$f3,
								$f4,
								$f5,
								$f6,
								$f7,
								$f8,
								$f9,
								$f10,
								$f11,
								$f12,
								$f13,
								$f14,
								$f15,
								$f16,
								$f17,
								$f18,
								$f19,
								$f20,
								$f21,
								$f22,
								$f23,
								$f24,
								$f25,
								$f26,
								$f27,
								$f28,
								$f29,
								$f30,
								$f31,
								$fcc,					//Float point condition code register
								$fcw,EOFR
						};


						MIPSProcessorState() 
						{
								// initialize registers to zero
								memset((void *)&regs, 0, sizeof(regs));
								memset((void *)&fp_regs, 0, sizeof(fp_regs));
						}


						MIPSProcessorState *getProcessorState()
						{
								return this;
						}
						// Get the memory address of the simulated register
						XTMemAddr get(XTRegNum reg) const
						{
								return (XTMemAddr) (regs + reg);
						}

						// Get the value of the simulated register
						XTInt32 reg(XTRegNum reg) const
						{
								//return static_cast<Word>( 0xffffffff & regs[reg]);
								return regs[reg];
						}

						// Set the value of simulated register
						void put(XTRegNum reg, XTInt32 value)
						{
								//		regs[reg] = static_cast<DWord>(~0) & value;
								regs[reg] = value;
						}

						// Get the number of *general-purpose* register
						int size() const
						{
								// $0-32, $hi, $lo
								return EOR;
						}

						XTMemAddr fpGet(XTRegNum reg) const
						{
								return (XTMemAddr) (fp_regs + reg);
						}

						// Get the value of the simulated register
						XTInt32 fpReg(XTRegNum reg) const
						{
								return fp_regs[reg];
						}

						// Set the value of simulated register
						void fpPut(XTRegNum reg, XTInt32 value)
						{
								fp_regs[reg] = value;
						}

						// Get the number of float-point register
						int fpSize() const
						{
								// $0-31, $fcc
								return EOFR;
						}

						MIPSProcessorState( const MIPSProcessorState& state )
						{
								int i;

								for( i = 0; i < size(); i ++ )
								{
										regs[i] = state.regs[i];
								}

								for( i = 0; i < fpSize(); i ++ )
								{
										fp_regs[i] = state.fp_regs[i];
								}
						}

						const MIPSProcessorState& operator= ( const MIPSProcessorState& state )
						{
								int i;

								for( i = 0; i < size(); i ++ )
								{
										regs[i] = state.regs[i];
								}

								for( i = 0; i < fpSize(); i ++ )
								{
										fp_regs[i] = state.fp_regs[i];
								}
								return *this;
						}

						void dumpToFile( XTFile fd );

						void loadFromFile( XTFile fd );

						// Dump the register file
						void dump();

				private:
						volatile XTInt32 regs[EOR];
						volatile XTInt32 fp_regs[EOFR];
		};

}

#endif
